/*
 *  EventManager.cpp
 *  Rempart
 *
 *
 */

#include "EventManager.h"

EventManager* EventManager::instance(0);

EventManager * EventManager::getInstance() {
	
	if (instance == 0) {
		instance = new EventManager();
	}
	return instance;
}


EventManager::EventManager(){
	this->totalTime = 0;
	this->boatFireTime = 0;
	this->mapDumpLock = false;
	this->mapLoadLock = false;
	this->mouseLeftLock = false;
	this->mouseRightLock = false;
	this->pattern = new MouseOverPattern();
	this->currentStage = noninit;
	this->gameClock = new sf::Clock();
}

EventManager::~EventManager(){
	this->stopLoop();
	this->Wait();
	delete this->pattern;
	delete this->gameClock;
	printf("EventManager détruit.\n");
}

int EventManager::getCurrentStage(){
	return this->currentStage;
}

float EventManager::getElapsedTime(){
	return this->elapsedTime;
}

const sf::Vector2<int>& EventManager::getMouseCasePosition(){
	return this->mouseCasePosition;
}

const sf::Vector2<float>& EventManager::getMousePosition(){
	return this->mousePosition;
}

const sf::Vector2<float>& EventManager::getMouseMapRelativePosition(){
	return this->mouseMapRelativePosition;
}



void EventManager::Run(){
	this->loop = true;
	this->freeze = false;
	while (this->loop) {
		if (!this->freeze) {
			this->processEvents();
		}
		sf::Sleep(0.01);
	}
}

void EventManager::processMouseManagement(){
	const sf::Input& input= GUI::getInstance()->GetInput();
	
	this->mousePosition = sf::Vector2<float>(input.GetMouseX(),input.GetMouseY());
	this->mouseMapRelativePosition = sf::Vector2<float>(input.GetMouseX()-Map::getInstance()->GetPosition().x,input.GetMouseY()-Map::getInstance()->GetPosition().y);
	this->mouseCasePosition = sf::Vector2<int>(round(this->mouseMapRelativePosition.x)/MapElement::getWidth(),round(this->mouseMapRelativePosition.y)/MapElement::getHeigth());
	
}


void EventManager::processStageManagement(){
	int currentPhaseTime = ((int) this->totalTime % 50);
	
	if (0 <= currentPhaseTime && currentPhaseTime < 30) {
		this->startStage(wall);
	}
	else if (30 <= currentPhaseTime && currentPhaseTime < 35 ) {
		this->startStage(canons);
	}
	else if (35 <= currentPhaseTime && currentPhaseTime < 50) {
		this->startStage(attack);
	}
	
	
}





void EventManager::processEvents(){
	
	
	this->elapsedTime = this->gameClock->GetElapsedTime();
	this->totalTime +=this->elapsedTime;
    this->gameClock->Reset();
	this->processStageManagement();
	this->processMouseManagement();
	
	const sf::Input& input= GUI::getInstance()->GetInput();
	
	
	Cursor::getInstance()->SetPosition(this->mousePosition);
	
	if(input.IsMouseButtonDown(sf::Mouse::Left)){
		this->mouseLeftLock = true;
	}
	if(input.IsMouseButtonDown(sf::Mouse::Right)){
		this->mouseRightLock = true;
	}
	
	switch (this->currentStage) {
		case wall:
			if (!input.IsMouseButtonDown(sf::Mouse::Left) && this->mouseLeftLock) {
				this->mouseLeftLock = false;
				try{
					Map::getInstance()->buildWall();
					delete this->pattern;
					this->pattern = new MouseOverPattern();
				}
				catch (CollisionException) {
				}
			}
				
				
			if (!input.IsMouseButtonDown(sf::Mouse::Right) && this->mouseRightLock) {
				this->mouseRightLock = false;
				this->pattern->rotate();
			}
				
		
		break;
		
		case canons:
			if (!input.IsMouseButtonDown(sf::Mouse::Left) && this->mouseLeftLock) {
				this->mouseLeftLock = false;
						
				try{
					Map::getInstance()->buildCanon();
				}
				catch (CollisionException) {
					// afficher peut être un message d'information, genre "on peut pas construire ici".
				}
			}
		break;
		
		case attack:
			this->boatFireTime += this->elapsedTime;
			
			
			// Gestion des collision des bullets, et de leur destruction.
			Map::getInstance()->manageWeapons();
			
			
			if (!input.IsMouseButtonDown(sf::Mouse::Left) && this->mouseLeftLock) {
				Map::getInstance()->triggerFire();
			}
			if (this->boatFireTime > 1){
				this->boatFireTime = 0.0;
				Map::getInstance()->triggerBoatFire();
				if(sf::Randomizer::Random(0,100) > 75){
					Map::getInstance()->buildBoat();
				}
			}
			
			if (!input.IsMouseButtonDown(sf::Mouse::Right) && this->mouseRightLock) {
				this->mouseRightLock = false;
				Map::getInstance()->buildBoat();
			}
			
			break;

		
		default:
			break;
	}
	
	
	if(input.IsMouseButtonDown(sf::Mouse::Left)){
		this->mouseLeftLock = true;
	}
	if (!input.IsMouseButtonDown(sf::Mouse::Left) && this->mouseLeftLock) {
		this->mouseLeftLock = false;
		switch (this->currentStage) {
			
				
			

			case attack:
				Map::getInstance()->triggerFire();
				break;
			default:
				break;
		}
		
	}
	
	
	if(input.IsKeyDown(sf::Key::D)){
		this->mapDumpLock = true;
	}
	if(!input.IsKeyDown(sf::Key::D) && this->mapDumpLock){
		this->mapDumpLock = false;
		//GUI::getInstance()->save();

	}
	
	if(input.IsKeyDown(sf::Key::R)){
		this->mapLoadLock = true;
	}
	if(!input.IsKeyDown(sf::Key::R) && this->mapLoadLock){
		this->mapLoadLock = false;
	//	GUI::getInstance()->restore();
		this->nextStage();
		
	}
	
	
	switch(this->currentStage) {
		case wall:
			Map::getInstance()->setMouseOver(pattern,this->mouseCasePosition.x,this->mouseCasePosition.y );
			break;
	}
	
	
}

void EventManager::nextStage(){
	printf("Entrée dans la phase %d\n",(this->currentStage+1)%3);
	this->startStage((this->currentStage+1)%3);
}

void EventManager::startStage(int phase){
	if (this->currentStage != phase) {
		this->currentStage = phase % 4;
		printf("Initiation de la phase %d.\n",phase);
		switch (this->currentStage) {
			case wall:
				NotificationsManager::getInstance()->display(RessourcesManager::getStageScreen(this->currentStage), 1.7, true, true);
				printf("Destruction des bateaux..\n");
				Map::getInstance()->destroyAllBoats();
				printf("Bateaux détruits.\n");
				printf("Mise à jour des zones..\n");
				Map::getInstance()->updateZones();
				printf("Zones mises à jour.\n");
				NotificationsManager::getInstance()->Wait();
			break;
			case canons:
				Map::getInstance()->unsetMouseOver();
				if(Map::getInstance()->getSecuredTowerNumber() < 1){
					this->gameOver();
				}
				NotificationsManager::getInstance()->display(RessourcesManager::getStageScreen(this->currentStage), 1.7, true, true);
			break;
			case attack:
				NotificationsManager::getInstance()->display(RessourcesManager::getStageScreen(this->currentStage), 1.7, true, true);
				for (int i = 0; i < this->totalTime/50; i++) {
					Map::getInstance()->buildBoat();
				}
				NotificationsManager::getInstance()->Wait();
			break;

			default:
				break;
		}
		printf("Phase %d initiée!\n", phase);
	}
}

void EventManager::stopLoop(){
	Map::getInstance()->unsetMouseOver();
	this->loop = false;
}

void EventManager::freezeLoop(){
	Map::getInstance()->unsetMouseOver();
	this->freeze = true;
}
void EventManager::continueLoop(){
	this->freeze=true;
}


void EventManager::gameOver(){
	printf("Game Over. Partie terminée\n");
	NotificationsManager::getInstance()->display(RessourcesManager::getLooseSplashScreenSurface(), 3, true, false);
	GUI::getInstance()->Close();
}